﻿using System;
using System.Linq;
using System.Collections.Generic;
using Newtonsoft.Json;
using T.FAS.Runtime.DataModel.Dao;
using T.FAS.Runtime.Metadata.Entity.DataModel;
using T.FAS.Runtime.Metadata.Entity;
using T.FAS.Runtime.Base.Entity;

namespace T.FAS.Runtime.DataModel.Plugin
{
    public class CompositeDataObjectRTPManager : AbsRTPMetaDataManager
    {
        public const string MetaDataID = DataModelConst.CDOMetaType;
        public const string MetaDataName = "复合数据对象";
        private readonly CompositeDataObjectLogic _compositeDataObjectLogic = new CompositeDataObjectLogic();
        private readonly DatabaseLogic _databaseLogic = new DatabaseLogic();
        private readonly StateMachineMetadataLogic _stateMachineLogic = new StateMachineMetadataLogic();        
        protected virtual CompositeDataObjectManager CompositeDataObjectManager { get; set; } = new CompositeDataObjectManager();
        public override IMetaDataContent GetMetaDataContent(string metaDataId)
        {
            if (string.IsNullOrEmpty(metaDataId))
                throw new FasException(DataModelErrorCode.CDO.RetrieveError, $"{MetaDataName}id为空");
            var cdo = _compositeDataObjectLogic.GetCompositeDataObject(metaDataId);
            if (cdo == null)
            {
                throw new FasException(DataModelErrorCode.CDO.RetrieveError, $"{MetaDataName}:{metaDataId}不存在，请检查!");
            }
            cdo.MetaDataID = cdo.ID;
            cdo.MetaDataCode = cdo.Code;
            cdo.MetaDataName = cdo.Name;
            //在运行时访问DB中CDO元数据时，同时填充好被依赖的SM
            FillStateMachine(cdo);
            //等待震哥更新RTPClient方法后，将数据组装部分放到Deserialize中，减少缓存Json大小以及缓存的旧数据
            //PackagingDependencyMetaData(cdo);
            return cdo;
        }

        public override string SerializeObject(IMetaDataContent metadata, MetadataSerializeType serializeType)
        {
            if (serializeType == MetadataSerializeType.JSON)
            {
                //(metadata as CompositeDataObject).ClearRef();

                return JsonConvert.SerializeObject(metadata, new JsonSerializerSettings
                {
                    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                });
            }
            else
            {
                throw new NotImplementedException();
            }
        }

        public override IMetaDataContent DeserializeObject(string metaDataString, MetadataSerializeType serializeType)
        {
            if(serializeType == MetadataSerializeType.JSON)
            {
                return DeserializeObject(metaDataString, true);
            }
            else
            {
                throw new NotImplementedException();
            }
        }

        public override IMetaDataContent DeserializeObject(string metaDataString, bool isPackingData = false)
        {
            if (string.IsNullOrEmpty(metaDataString))
                throw new FasException(DataModelErrorCode.Error, $"CDO反序列化Json不能为空，请检查！");
            var cdo = JsonConvert.DeserializeObject<CompositeDataObject>(metaDataString, new JsonSerializerSettings
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore
            });

            if (isPackingData)
                PackagingDependencyMetaData(cdo);

            return cdo;
        }

        public override void Import(List<IMetaDataContent> contents)
        {
            CompositeDataObjectManager.Import(contents);
        }

        public override void Delete(List<string> IDs)
        {
            CompositeDataObjectManager.Delete(IDs);
        }
        #region Private Funcs

        private void FillStateMachine(CompositeDataObject cdo)
        {
            if (cdo == null) return;
            var sms = _stateMachineLogic.GetStateMachineMetadatas(cdo.ID);
            foreach (var ele in cdo.RootCompositeNodeObject.Elements)
            {
                var colSms = sms.Where(sm => sm.CDOColKey == (ele.Alias ?? ele.Name)).ToList();
                if (colSms.Count > 0)
                {
                    if (ele.StateMachines == null)
                        ele.StateMachines = new List<StateMachineMetadata>();
                    ele.StateMachines.AddRange(colSms);
                }
            }
        }

        public void PackagingDependencyMetaData(IMetaDataContent metaData)
        {
            var cdo = metaData as CompositeDataObject;
            if (cdo == null)
                return;
            var unifyCode = DataModelErrorCode.GetUnifiedErrorCode(MetaDataID, cdo.ID, cdo.Code);
            try
            {
                //当CDO的Nodes节点为空时，从DB中拉取完整CDO元数据
                if (cdo.CompositeNodeObjects == null || cdo.CompositeNodeObjects.Count == 0)
                    throw new FasException(DataModelErrorCode.CDO.InitError, $"{cdo.Code}元数据信息不完整");
                cdo.RootCompositeNodeObject = cdo.CompositeNodeObjects.Find(cno => cno.IsRootObject);
                foreach (var cno in cdo.CompositeNodeObjects)
                {
                    if (cno.DataObject == null)
                        cno.DataObject = GetMetaData<DataObject>(cno.DataObjectID);
                    if (cno.DataObject?.Database == null && cno.DataObject != null)
                        cno.DataObject.Database = _databaseLogic.GetDatabaseByID(cno.DataObject.DatabaseID);
                    var outerAssos = cno.Associations.Where(o => o.AssociateType == AssociateType.OuterLeftJoin).ToList();
                    var refeles = outerAssos.SelectMany(outer => outer.RefElements).ToList();
                    //初始化Element对应的DataColumn属性
                    if (cno.Elements != null && cno.Elements.Count > 0)
                    {
                        foreach (var ele in cno.Elements)
                        {
                            if (ele.ElementType == ElementType.Normal)   //初始化所有Normal Element对应的DataColumn对象
                            {
                                ele.DataColumn = cno.DataObject.Columns.Find(col => col.ID == ele.DataColumnID);
                            }  
                        }
                    }
                    cno.ChildCompositeNodeObjects = cdo.CompositeNodeObjects
                                                        .Where(o => o.ParentObjectID == cno.ID)
                                                        .OrderBy(o => o.ID)
                                                        .ToList();
                    cno.ChildCompositeNodeObjects.ForEach(child => child.ParentObject = cno);
                    //构造关联关系实体引用
                    if (cno.Associations != null && cno.Associations.Count > 0)
                    {
                        foreach (var asso in cno.Associations)
                        {
                            if (asso.AssociateType == AssociateType.InnerJoin)
                            {
                                asso.AssoDomaiModel = cdo;
                                asso.AssoCompositeNodeObject = cdo.CompositeNodeObjects.Find(o => o.ID == asso.AssoCompositeNodeObjectID);
                            }
                            else if (asso.AssociateType == AssociateType.OuterLeftJoin)
                            {
                                asso.AssoDataObject = GetMetaData<DataObject>(asso.AssoDataObjectID);
                            }
                        }
                    }
                } 
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.DQ.InitError, $"{unifyCode}数据组装失败，请检查！", e);
            }
        }

        public override IRefSchemaEntity BuildRefSchema(IMetaDataContent metaDataContent)
        {
            if (metaDataContent is CompositeDataObject cdo)
            {
                return cdo.BuildRefSchema();
            }
            else
            {
                throw new ArgumentNullException(nameof(metaDataContent));
            }
        }

        public override IEnumerable<Metadata.Entity.Term> BuildTerms(IMetaDataContent metaDataContent, IEnumerable<Metadata.Entity.Term> termList = null)
        {
            return default;
        }


        public override IRefSchemaEntity DeserializeRefSchemaEntity(string schemaEntityJson)
        {
            return JsonConvert.DeserializeObject<CompositeDataObjectRefSchemaEntity>(schemaEntityJson);
        }

        #endregion

        #region FASRM Methods
        /******************转调Dev.Plugin Manager实现********************/

        ///// <summary>
        ///// 元数据保存
        ///// </summary>
        ///// <param name="metaData"></param>
        //public override void Save(IMetaDataContent metaData)
        //{
        //    CompositeDataObjectManager.Save(metaData);
        //}

        ///// <summary>
        ///// 元数据删除
        ///// </summary>
        ///// <param name="metaData"></param>                                                                                                                                                                                                                                                                                                                                                     
        //public override void Delete(IMetaDataContent metaData)
        //{
        //    CompositeDataObjectManager.Delete(metaData);
        //}

        ///// <summary>
        ///// 修改DO元数据
        ///// 1:检测新DO与旧DO之间的列差异（通过DO.Column.ID字段区分，即界面上删除Name字段再添加Name字段，CNO.Elements算作先删后加）
        ///// 2:根据CNO.DataObjectID查找所有DO引用
        ///// 3:事务内同步修改所有CNO下的Element以及DO
        ///// 4:是否需要做更新后CDO有效性验证。
        ///// </summary>
        ///// <param name="metaData"></param>
        //public override void Update(IMetaDataContent metaData)
        //{
        //    CompositeDataObjectManager.Update(metaData);
        //}

        ////public override void PackagingDependencyMetaData(IMetaDataContent metaData)
        ////{
        ////    CompositeDataObjectManager.PackagingDependencyMetaData(metaData);
        ////}

        //public override ValidateResult Validate(IMetaDataContent metaData)
        //{
        //    return CompositeDataObjectManager.Validate(metaData);
        //}

        //public override ConflictMessage ConflictCheck(List<IMetaDataContent> releasedMetaData, IMetaDataContent releaseingMetaData)
        //{
        //    return CompositeDataObjectManager.ConflictCheck(releasedMetaData, releaseingMetaData);
        //}

        //public override MetaDataCompileResult Compile(IList<IMetaDataContent> metadatas)
        //{
        //    return CompositeDataObjectManager.Compile(metadatas);
        //}

        //public override void Import(List<IMetaDataContent> metaDatas)
        //{
        //    CompositeDataObjectManager.Import(metaDatas);
        //}

        //public override void Delete(List<IMetaDataContent> metaDatas)
        //{
        //    CompositeDataObjectManager.Delete(metaDatas);
        //}

        ///// <summary>
        ///// DataObject元数据启用
        ///// </summary>
        ///// <param name="metaDatas">DataObject元数据</param>
        //public override void Enable(params IMetaDataContent[] metaDatas)
        //{
        //    CompositeDataObjectManager.Enable(metaDatas);
        //}



        //#region Private Funcs
        ///// <summary>
        ///// 校验
        ///// </summary>
        ///// <param name="cdo"></param>
        ///// <param name="type"></param>
        //private void Validate(IMetaDataContent cdo, CRUDType type)
        //{
        //    if (!ConfigTool.IsDebug(MetaDataID)) return;
        //    IMetaDataDesignValidator doValidator = new DataObjectValidator();
        //    if (type == CRUDType.RETRIEVE)
        //        doValidator.GetMetadata(cdo);
        //    else if (type == CRUDType.CREATE)
        //        doValidator.CreateMetadata(cdo);
        //    else if (type == CRUDType.DELETE)
        //        doValidator.DeleteMetadata(cdo);
        //    else if (type == CRUDType.UPDATE)
        //        doValidator.UpdateMetadata(cdo);
        //}

        //public override List<MetaDataDependency> GetMetaDataDependencys(IMetaDataContent metaDataContent)
        //{
        //    throw new NotImplementedException();
        //}

        //public override MetaDataUpdateSet GetMetaDataUpdateSet(IMetaDataContent oldMetaData, IMetaDataContent newMetaData)
        //{
        //    throw new NotImplementedException();
        //}

        //public override MetaUpdateResult UpdateDependencyMetaData(IMetaDataContent metaDataContent, MetaDataUpdateSet updateSet)
        //{
        //    throw new NotImplementedException();
        //}

        //#endregion
        #endregion
    }
}
